package com.itheima.stock.service.impl;

import com.google.common.collect.Lists;
import com.itheima.stock.config.StockInfoConfig;
import com.itheima.stock.mapper.StockBlockRtInfoMapper;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.StockBlockRtInfo;
import com.itheima.stock.pojo.StockMarketIndexInfo;
import com.itheima.stock.service.StockTimerTaskService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.utils.ParseType;
import com.itheima.stock.utils.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author GAQ
 * @create 2022-06-05
 * @Description
 */
@Service
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {

    /**
     * 注入httpClient bean，调用远程api接口
     */
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 注入股票参数配置类，方便获取股票相关的url地址信息
     */
    @Autowired
    private StockInfoConfig stockInfoConfig;

    /**
     * 注入id生成器
     */
    @Autowired
    private IdWorker idWorker;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private ParserStockInfoUtil parserStockInfoUtil;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    /**
     * 获取国内大盘的实时数据
     */
    @Override
    public void getInnerMarketInfo() {
        //1.组装url地址
        String innerMarketUrl = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getInner());
        //2.其他参数
        String referer = "https://finance.sina.com.cn/stock/";
        String userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36";
        //3.组装http组装对象
        //3.1组装请求头
        HttpHeaders headers = new HttpHeaders();
        headers.add("referer", referer);
        headers.add("User-Agent", userAgent);
        //3.2组装请求对象
        HttpEntity<Object> entity = new HttpEntity<>(headers);
        //4.发送请求
        String result = restTemplate.postForObject(innerMarketUrl, entity, String.class);
        //定义公共正则表达式
        String reg = "var hq_str_(.+)=\"(.+)\";";
        //编译表达式，获取编译对象
        Pattern pattern = Pattern.compile(reg);
        //匹配字符串
        Matcher matcher = pattern.matcher(result);
        ArrayList<StockMarketIndexInfo> list = new ArrayList<>();
        //判断是否有匹配值
        while (matcher.find()) {
            //获取大盘的code
            String marketCode = matcher.group(1);
            //获取其它信息，字符串以逗号间隔
            String otherInfo = matcher.group(2);
            //以逗号切割字符串，形成数组
            String[] splitArr = otherInfo.split(",");
            //大盘名称
            String marketName = splitArr[0];
            //获取当前大盘的开盘点数
            BigDecimal openPoint = new BigDecimal(splitArr[1]);
            //前收盘点
            BigDecimal preClosePoint = new BigDecimal(splitArr[2]);
            //获取大盘的当前点数
            BigDecimal curPoint = new BigDecimal(splitArr[3]);
            //获取大盘最高点
            BigDecimal maxPoint = new BigDecimal(splitArr[4]);
            //获取大盘的最低点
            BigDecimal minPoint = new BigDecimal(splitArr[5]);
            //获取成交量
            Long tradeAmt = Long.valueOf(splitArr[8]);
            //获取成交金额
            BigDecimal tradeVol = new BigDecimal(splitArr[9]);
            //时间
            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();

            //组装entity对象
            StockMarketIndexInfo info = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId() + "")
                    .marketCode(marketCode)
                    .marketName(marketName)
                    .curPoint(curPoint)
                    .openPoint(openPoint)
                    .preClosePoint(preClosePoint)
                    .maxPoint(maxPoint)
                    .minPoint(minPoint)
                    .tradeVolume(tradeVol)
                    .tradeAmount(tradeAmt)
                    .curTime(curTime)
                    .build();
            //收集封装的对象，方便批量插入
            list.add(info);
        }
        log.info("当前采集的数据数量：{},内容：{}", list.size(), list);
        //批量插入
        int count = stockMarketIndexInfoMapper.insertBatch(list);
        log.info("当前插入了：{}条数据", count);
    }

    /**
     * 采集A股实时数据方法
     */
    @Override
    public void getStockAShare() {
        //1.获取所有A股股票的编码
        List<String> codes = stockBusinessMapper.getAllStockCodes();

        //2.添加股票前缀 sh sz
        List<String> prefixCodes = codes.stream().map(code -> {
            code = code.startsWith("6") ? "sh" + code : "sz" + code;
            return code;
        }).collect(Collectors.toList());
        //设置请求头的请求参数
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        HttpEntity<Object> entity = new HttpEntity<>(headers);

        //3.将股票编码集合分片处理（每片大小15，一次性查询15支股票）
        Lists.partition(prefixCodes, 15).stream().forEach(codeList -> {
            //4.组装请求数据
            String url = stockInfoConfig.getMarketUrl() + String.join(",", codeList);
            //5.请求获取数据
            String result = restTemplate.postForObject(url, entity, String.class);
            if (result == null) {
                return;
            }
            //6.解析数据，封装对象
            List list = parserStockInfoUtil.parser4StockOrMarketInfo(result, ParseType.ASHARE);

            //7.批量保存
            int count = stockRtInfoMapper.insertBatch(list);
            log.info("数据：{},总共{}条", list, count);
        });

    }

    /**
     * 获取板块数据方法
     */
    @Override
    public void getStockSectorRtIndex() {
        //发送板块数据请求
        String result = restTemplate.getForObject(stockInfoConfig.getBlockUrl(), String.class);
        //响应结果转板块集合数据
        List<StockBlockRtInfo> infos = parserStockInfoUtil.parse4StockBlock(result);
        log.info("板块数据量：{}", infos.size());

        //批量保存
        Lists.partition(infos, 20).forEach(list -> {
            stockBlockRtInfoMapper.insertBatch(list);
        });
    }
}
